package me

import (
	"bytes"
	"context"
	"fmt"
	"image"
	"os"
	"strconv"
	"strings"
	"time"

	"fyne.io/fyne/v2"
	fcv "fyne.io/fyne/v2/canvas"
	ct "fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/data/binding"
	"fyne.io/fyne/v2/theme"
	. "fyne.io/fyne/v2/widget"
	"gitee.com/y2h/fyneExplorer/imageviewer"
	"gitee.com/y2h/fyneExplorer/wdg"
	"github.com/auyer/steganography"
	"github.com/disintegration/imaging"
	"github.com/gogf/gf/v2/os/gfile"
	"github.com/gogf/gf/v2/os/gproc"
	"github.com/gogf/gf/v2/text/gstr"
	"github.com/gogf/gf/v2/util/gconv"
)

func ViewImage(imgfile string) {
	// 原图
	SelectedPath = imgfile
	var img image.Image
	var err error
	emptyImg := &image.NRGBA{}
	img0 := fcv.NewImageFromImage(emptyImg)
	img0.FillMode = fcv.ImageFillContain

	LblMsg := NewLabel("")
	btnSrc := NewButton("原图", func() {
		img0.Image = img
		img0.Refresh()
		Msg("原图")
	})
	btnSplit := NewButton("分割", func() {
		Split(img)
	})

	btnPrev := NewButtonWithIcon("", theme.MediaSkipPreviousIcon(), func() {
		PrevView(IsImage, func(furi fyne.URI) {
			ViewImage(furi.Path())
		})
	})
	btnNext := NewButtonWithIcon("", theme.MediaSkipNextIcon(), func() {
		NextView(IsImage, func(furi fyne.URI) {
			ViewImage(furi.Path())
		})
	})

	btnOcr := NewButton("Ocr", func() {
		Ocr(imgfile)
	})
	btnViewer := NewButton("Viewer", func() {
		imageviewer.UI(fyne.CurrentApp(), imgfile)
	})
	btnHide := NewButton("隐藏信息", func() {
		HideTxt()
	})

	SetObjs(Right, ct.NewBorder(ct.NewHBox(btnPrev, btnNext,
		btnSrc, btnSplit, btnOcr, btnViewer, btnHide),
		ct.NewHBox(CvsMsg, LblMsg), nil, nil, img0))

	AsyncCall1(5, func() {
		t1 := time.Now()
		img, err = imaging.Open(imgfile, imaging.AutoOrientation(true))
		if err != nil || img == nil {
			Msg("Image Decode error:" + err.Error())
			return
		}
		CvsMsg.Text = gconv.String(time.Since(t1).Milliseconds()) + " ms Used."
		CvsMsg.Refresh()
		srcW := img.Bounds().Dx()
		srcH := img.Bounds().Dy()
		if srcW <= 0 || srcH <= 0 {
		} else {
			img0.Image = imaging.Resize(img, 800, 0, imaging.Lanczos)
			LblMsg.SetText(fmt.Sprintf("%d X %d | 调整到宽度800", srcW, srcH))
		}
	}, func() {
		Msg("读取文件超时,请使用系统默认应用程序打开")
	})

	img0.Refresh()
}

// 将信息隐藏到图片中
func HideTxt() {
	w0 := fyne.CurrentApp().NewWindow("信息隐藏")
	w0.Resize(fyne.NewSquareSize(700))
	imga, _ := imaging.Open(SelectedPath)
	img0 := fcv.NewImageFromImage(imga)
	img0.FillMode = fcv.ImageFillContain
	img1 := fcv.NewImageFromImage(imga)
	img1.FillMode = fcv.ImageFillContain
	en0 := NewEntry()
	en0.PlaceHolder = "Input some information here to hide"
	split0 := ct.NewHSplit(img0, en0)
	cvsMsg := fcv.NewText("", Red)
	fpath := ""
	openFile := wdg.NewOpenFile1(binding.BindString(&fpath), ExtImage, func() {
		img1.Image, _ = imaging.Open(fpath)
		img1.Refresh()
	}, w0)
	opts := []string{"藏图片", "藏信息"}
	rg1 := NewRadioGroup(opts, func(s string) {
		switch s {
		case opts[0]:
			split0.Trailing = ct.NewBorder(openFile, nil, nil, nil, img1)
			split0.Refresh()
		default:
			split0.Trailing = en0
			split0.Refresh()
		}
	})
	rg1.Horizontal = true
	encode := func(bs []byte) {
		ib := new(bytes.Buffer)
		err := steganography.Encode(ib, img0.Image, bs)
		if err != nil {
			cvsMsg.Text = err.Error()
			cvsMsg.Refresh()
			return
		}
		img0.Image, _ = imaging.Decode(ib)
		err = imaging.Save(img0.Image, SelectedPath)
		if err != nil {
			cvsMsg.Text = "Save image error :" + err.Error()
			cvsMsg.Refresh()
			return
		}

		cvsMsg.Text = "Done"
		cvsMsg.Refresh()
	}
	btnEncodeImg := NewButton("Encode Image", func() {
		var bs []byte
		var err error
		bs, err = os.ReadFile(fpath)
		if err != nil {
			return
		}
		encode(bs)
	})
	btnEncodeTxt := NewButton("Encode Text", func() {
		if strings.TrimSpace(en0.Text) == "" {
			cvsMsg.Text = "Please input some strings to hide"
			cvsMsg.Refresh()
			return
		}
		encode([]byte(en0.Text))
	})

	decode := func() (bs []byte) {
		sizeOfMessage := steganography.GetMessageSizeFromImage(img0.Image)
		if sizeOfMessage <= 0 {
			cvsMsg.Text = "No information hide"
			cvsMsg.Refresh()
			bs = nil
		}
		bs = steganography.Decode(sizeOfMessage, img0.Image)
		return
	}
	btnDecodeImg := NewButton("Decode Image", func() {
		msg := decode()
		if msg == nil {
			return
		}
		img1.Image, _ = imaging.Decode(bytes.NewReader(msg))
		img1.Refresh()
	})
	btnDecodeTxt := NewButton("Decode Text", func() {
		msg := decode()
		if msg == nil {
			return
		}
		en0.SetText(string(msg))
	})
	top := ct.NewHBox(rg1, btnEncodeTxt, btnEncodeImg, btnDecodeTxt, btnDecodeImg)

	c0 := ct.NewBorder(top, cvsMsg, nil, nil, split0)
	w0.SetContent(c0)
	w0.Show()
}

func Ocr(imgfile string) {
	w := fyne.CurrentApp().NewWindow("OCR tesseract")
	exepath := NewEntry()
	msg := NewLabel("")
	right := NewMultiLineEntry()
	right.Wrapping = fyne.TextWrapBreak
	exepath.SetText(`E:\soft\Tesseract-OCR\tesseract.exe`)
	img := fcv.NewImageFromFile(imgfile)
	img.FillMode = fcv.ImageFillContain

	btnDo := NewButton("Ocr", func() {
		exe := exepath.Text + ` ` + img.File + ` - -l chi_sim`
		msg.SetText(exe)
		r, err := gproc.ShellExec(context.Background(), exe)
		if err != nil {
			right.SetText(err.Error())
			return
		}
		r = gstr.TrimAll(r, " ")
		right.SetText(r)
	})
	top := ct.NewVBox(exepath, btnDo)
	split := ct.NewHSplit(img, right)
	w.SetContent(ct.NewBorder(top, msg, nil, nil, split))
	w.Resize(fyne.NewSize(800, 700))
	w.Show()
}

type rect struct {
	rect0  image.Rectangle
	suffix string
}

func Split(img image.Image) {
	w0 := fyne.CurrentApp().NewWindow("图片分割")
	w0.Resize(fyne.NewSquareSize(700))
	img0 := fcv.NewImageFromImage(img)
	img0.FillMode = fcv.ImageFillContain

	cvsMsg := fcv.NewText("", Red)

	wh := func() (int, int) {
		return img0.Image.Bounds().Max.X, img0.Image.Bounds().Max.Y
	}
	refresh := func(msg string) {
		cvsMsg.Text = msg
		cvsMsg.Refresh()
		RefreshDir()
	}
	chkSplit := NewCheck("Spilt", func(b bool) {
	})
	src := img0.Image
	// 将图片左右平均分割
	btnLR := NewButton("LR", func() {
		mw, mh := wh()
		w1 := mw / 2

		rects0 := []rect{
			{image.Rect(0, 0, w1, mh), "left"},
			{image.Rect(w1, 0, mw, mh), "right"},
		}

		// 红色的竖线
		line0 := imaging.New(5, mh, Red)
		img0.Image = imaging.Paste(img0.Image, line0, image.Pt(w1, 0))
		img0.Refresh()

		if !chkSplit.Checked {
			return
		}
		crops(src, rects0)
		// crops(img0.Image, rects0)
		refresh("left-right split done")
	})
	// 将图片上下平均分割
	btnTB := NewButton("TB", func() {
		mw, mh := wh()
		h1 := mh / 2

		rects0 := []rect{
			{image.Rect(0, 0, mw, h1), "top"},
			{image.Rect(0, h1, mw, mh), "bottom"},
		}

		line0 := imaging.New(mw, 5, Red)
		img0.Image = imaging.Paste(img0.Image, line0, image.Pt(0, h1))
		img0.Refresh()

		if !chkSplit.Checked {
			return
		}
		crops(src, rects0)
		// crops(img0.Image, rects0)
		refresh("top-bottom split done")
	})

	// 将图片平均分割成4份
	btn4 := NewButton("4", func() {
		mw, mh := wh()
		h1 := mh / 2
		w1 := mw / 2

		line0 := imaging.New(5, mh, Red)
		img0.Image = imaging.Paste(img0.Image, line0, image.Pt(w1, 0))
		line1 := imaging.New(mw, 5, Red)
		img0.Image = imaging.Paste(img0.Image, line1, image.Pt(0, h1))
		img0.Refresh()

		if !chkSplit.Checked {
			return
		}
		i := 1
		DoRect(mw, mh, 2, 2, func(r image.Rectangle) {
			crop(src, r, "4_"+strconv.Itoa(i))
			// crop(img0.Image, r, "4_"+strconv.Itoa(i))
			i++
		})

		refresh("split 4 done")
	})
	// 将图片平均分割成9份
	btn9 := NewButton("9", func() {
		mw, mh := wh()
		h1 := mh / 3
		w1 := mw / 3

		line0 := imaging.New(5, mh, Red)
		line1 := imaging.New(mw, 5, Red)
		for i := 1; i < 3; i++ {
			img0.Image = imaging.Paste(img0.Image, line0, image.Pt(w1*i, 0))
			img0.Image = imaging.Paste(img0.Image, line1, image.Pt(0, h1*i))
		}
		img0.Refresh()

		if !chkSplit.Checked {
			return
		}
		i := 1
		DoRect(mw, mh, 3, 3, func(r image.Rectangle) {
			crop(src, r, "9_"+strconv.Itoa(i))
			// crop(img0.Image, r, "9_"+strconv.Itoa(i))
			i++
		})

		refresh("split 9 done")
	})
	numSplit := 5
	numRow := 2
	numCol := 2
	en1 := NewEntryWithData(binding.IntToString(binding.BindInt(&numSplit)))
	enRow := NewEntryWithData(binding.IntToString(binding.BindInt(&numRow)))
	enRow.PlaceHolder = "行数"
	enCol := NewEntryWithData(binding.IntToString(binding.BindInt(&numCol)))
	enCol.PlaceHolder = "列数"
	// 从左到右水平平均分割图片
	btnHsplit := NewButton("HSplit", func() {
		mw, mh := wh()
		w1 := mw / numSplit

		line0 := imaging.New(5, mh, Red)
		for i := 1; i < numSplit; i++ {
			img0.Image = imaging.Paste(img0.Image, line0, image.Pt(w1*i, 0))
		}
		img0.Refresh()

		if !chkSplit.Checked {
			return
		}
		i := 1
		DoRect(mw, mh, 1, numSplit, func(r image.Rectangle) {
			crop(src, r, "h"+strconv.Itoa(i))
			// crop(img0.Image, r, "h"+strconv.Itoa(i))
			i++
		})

		refresh("HSplit " + en1.Text + " done")
	})
	// 从上到下垂直平均分割图片
	btnVsplit := NewButton("VSplit", func() {
		mw, mh := wh()
		h1 := mh / numSplit

		line1 := imaging.New(mw, 5, Red)
		for i := 1; i < numSplit; i++ {
			img0.Image = imaging.Paste(img0.Image, line1, image.Pt(0, h1*i))
		}
		img0.Refresh()

		if !chkSplit.Checked {
			return
		}
		i := 1
		DoRect(mw, mh, numSplit, 1, func(r image.Rectangle) {
			crop(src, r, "v"+strconv.Itoa(i))
			// crop(img0.Image, r, "v"+strconv.Itoa(i))
			i++
		})
		refresh("VSplit " + en1.Text + " done")
	})
	btnDo := NewButton("Split", func() {
		mw, mh := wh()
		h1 := mh / numRow
		w1 := mw / numCol

		line0 := imaging.New(5, mh, Red)
		line1 := imaging.New(mw, 5, Red)
		for i := 1; i < numCol; i++ {
			img0.Image = imaging.Paste(img0.Image, line0, image.Pt(w1*i, 0))
		}
		for i := 1; i < numRow; i++ {
			img0.Image = imaging.Paste(img0.Image, line1, image.Pt(0, h1*i))
		}
		img0.Refresh()

		if !chkSplit.Checked {
			return
		}
		i := 1
		DoRect(mw, mh, numRow, numCol, func(r image.Rectangle) {
			crop(src, r, strconv.Itoa(i))
			// crop(img0.Image, r, strconv.Itoa(i))
			i++
		})

		refresh("split done")
	})

	btnReset := NewButton("Reset", func() {
		img0.Image = src
		img0.Refresh()
	})
	top := ct.NewHBox(chkSplit, btnLR, btnTB, btn4, btn9, en1, btnHsplit, btnVsplit,
		enRow, enCol, btnDo, btnReset)

	c0 := ct.NewBorder(top, cvsMsg, nil, nil, img0)

	w0.SetContent(c0)
	w0.Show()
}

func crops(src image.Image, rects0 []rect) {
	for _, v := range rects0 {
		crop(src, v.rect0, v.suffix)
	}
}

// crop 将原始图片分割出一块进行保存
func crop(src image.Image, rect image.Rectangle, suffix string) {
	dst := imaging.Crop(src, rect)
	lfn := gfile.Join(gfile.Dir(SelectedPath),
		gfile.Name(SelectedPath)+"_"+suffix) + gfile.Ext(SelectedPath)
	imaging.Save(dst, lfn)
}

// 对区域进行分割，对分割块执行操作 fn
func DoRect(w, h, r, c int, fn func(image.Rectangle)) {
	w0, h0 := w/c, h/r
	rect0 := image.Rectangle{}
	for i := 0; i < c; i++ {
		for j := 0; j < r; j++ {
			rect0.Min = image.Pt(w0*i, h0*j)
			rect0.Max = image.Pt(w0*(i+1), h0*(j+1))
			fn(rect0)
		}
	}
}
